package edu.hawaii.ics314.ical.controller;

import java.io.File;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;

import edu.hawaii.ics314.ical.model.Calendar;
import edu.hawaii.ics314.ical.model.CalendarComponentInfo;
import edu.hawaii.ics314.ical.model.DateTime;
import edu.hawaii.ics314.ical.model.Event;
import edu.hawaii.ics314.ical.model.Property;
import edu.hawaii.ics314.ical.model.TimeZone;
import edu.hawaii.ics314.ical.model.CalendarComponent.ComponentPriority;
import edu.hawaii.ics314.ical.view.InputView;
import edu.hawaii.ics314.ical.view.ListSelectionView;
import edu.hawaii.ics314.ical.view.View;
import edu.hawaii.ics314.ical.view.ViewEvent;
import edu.hawaii.ics314.ical.view.ViewListener;

public class MainMenuView extends ListSelectionView<String>{
	
	private final File DEBUG_FILE = new File("checkin01_test.ics");
	
	public MainMenuView() {
		super("ICS 314 iCalendar Assignment", "", "Write Debug File (no read)", "Read Debug File (no write)", 
				"Create Event (check-in #1)", "Find Free Times (check-in #2)", "Find Common Free Times (check-in #3)", 
				"Exit");
		
		addViewListener(new ViewListener<String>() {
			public void onViewResult(ViewEvent<String> evt) {
				switch(evt.getIndex()) {
				case 0:
					// Check-in #1 values.
					Calendar dbgCal = 
						new Calendar(new Property<String>("VERSION", "2.0"), new CalendarComponentInfo());
					TimeZone dbgTimeZone = new TimeZone(new Property<String>("TZNAME", "America/Hawaii"),
							new Property<String>("TZID", "HST"), new Property<String>("OFFSETFROM", "-1000"),
							new Property<String>("OFFSETTO", "-1000"), false, new CalendarComponentInfo());
					CalendarComponentInfo dbgEvtCalCompInfo = new CalendarComponentInfo();
					dbgEvtCalCompInfo.classification = new Property<String>("CLASSIFICATION", "PUBLIC");
					dbgEvtCalCompInfo.endDateTime = 
							new Property<DateTime>("DTEND", new DateTime(2015, 5, 8, 20, 0, 0));
					dbgEvtCalCompInfo.startDateTime = 
							new Property<DateTime>("DTSTART", new DateTime(2015, 5, 8, 18, 0, 0));
					dbgEvtCalCompInfo.hostCalendar = dbgCal;
					dbgEvtCalCompInfo.location = new Property<String>("LOCATION", "Hamilton Library");
					dbgEvtCalCompInfo.priority = new Property<ComponentPriority>("PRIORITY", ComponentPriority.A1_HIGH);
					dbgEvtCalCompInfo.summary = new Property<String>("SUMMARY", "Studying for finals");
					dbgEvtCalCompInfo.timeZone = new Property<TimeZone>("TZID", dbgTimeZone);
					Event dbgEvent = new Event(dbgEvtCalCompInfo);
					dbgCal.addCalendarComponent(dbgEvent);
					try {
						/* Output to console */
						dbgCal.toOutputStream(System.out);
						/* Output to file */
						if(!DEBUG_FILE.exists()) {
							DEBUG_FILE.createNewFile();
						}
						dbgCal.toFile(DEBUG_FILE);
					} catch (IOException e) {
						System.out.println("An error occurred while writing calendar.\n\nError Detail:");
						e.printStackTrace(System.out);
						System.out.println();
						evt.getSource().show();
					}
					break;
				case 1:
					boolean readSuccessful = false;
					try {
						Calendar debugFileCal = Calendar.fromFile(DEBUG_FILE);
						readSuccessful = true;
						debugFileCal.toOutputStream(System.out);
					} catch (IOException | ParseException e) {
						System.out.println("An error occurred while " + (readSuccessful ? "writing" : "reading") 
								+ " calendar.\n\nError Detail:");
						e.printStackTrace(System.out);
						System.out.println();
						evt.getSource().show();
					}
					break;
				case 2:
					Calendar userEvtHostCal = 
						new Calendar(new Property<String>("VERSION", "2.0"), new CalendarComponentInfo());
					Event userEvent = promptCreateEvent();
					userEvtHostCal.addCalendarComponent(userEvent);
					try {
						/* Output to console */
						userEvtHostCal.toOutputStream(System.out);
						/* Output to file */
						if(!DEBUG_FILE.exists()) {
							DEBUG_FILE.createNewFile();
						}
						userEvtHostCal.toFile(DEBUG_FILE);
					} catch (IOException e) {
						System.out.println("An error occurred while writing calendar.\n\nError Detail:");
						e.printStackTrace(System.out);
						System.out.println();
						evt.getSource().show();
					}
					break;
				case 3:
					InputView checkInTwoView = new InputView("Input file list (comma-separated): ");
					checkInTwoView.addViewListener(new CheckInTwoViewController());
					checkInTwoView.show();
					break;
				case 4:
					InputView minPriorityDlg = new InputView("Priority Info:"
							+"\nInteger value 0-9."
							+ "\n0 = UNDEFINED, 1-->9 = HIGH-->LOW"
							+ "\nInclude events lower than following priority in free time (exclusive): ");
					minPriorityDlg.addViewListener(new ViewListener<String>() {
						@Override
						public void onViewResult(ViewEvent<String> evt) {
							ComponentPriority minPriThreshold;
							try {
								minPriThreshold = ComponentPriority.parse(evt.getResult());
								InputView checkInThreeView = new InputView("Input file list (comma-separated): ");
								checkInThreeView.addViewListener(new CheckInThreeViewController(minPriThreshold));
								checkInThreeView.show();
							} catch (ParseException e) {
								evt.getSource().show();
							}
						}
					});
					minPriorityDlg.show();
					break;
				case 6:
					System.exit(0);
					break;
				// Do not need default case because AbstractView guarantees that event will only
				// be fired on valid input.
				}
			}
		});
	}
	
	private Event promptCreateEvent() {
		final CalendarComponentInfo eventInfo = new CalendarComponentInfo();
		final TimeZoneInfo tzInfo = new TimeZoneInfo();
		View<String> curView = null;
		// Classification
		curView = new InputView("Classification: ");
		curView.addViewListener(new ViewListener<String>() {
			public void onViewResult(ViewEvent<String> evt) {
				eventInfo.classification = new Property<String>("CLASSIFICATION", evt.getResult());
			}
		});
		curView.show();
		// Location
		curView = new InputView("Location: ");
		curView.addViewListener(new ViewListener<String>() {
			public void onViewResult(ViewEvent<String> evt) {
				eventInfo.location = new Property<String>("LOCATION", evt.getResult());
			}
		});
		curView.show();
		// Priority
		curView = new InputView("Priority (integer >= 0): ");
		curView.addViewListener(new ViewListener<String>() {
			public void onViewResult(ViewEvent<String> evt) {
				try {
					eventInfo.priority = new Property<ComponentPriority>("PRIORITY", ComponentPriority.parse(evt.getResult()));
				} catch(ParseException e) {
					if(!evt.getResult().isEmpty()) {
						evt.getSource().show();
					}
				}
			}
		});
		curView.show();
		// Summary
		curView = new InputView("Summary: ");
		curView.addViewListener(new ViewListener<String>() {
			public void onViewResult(ViewEvent<String> evt) {
				eventInfo.summary = new Property<String>("SUMMARY", evt.getResult());
			}
		});
		curView.show();
		// Start DateTime
		final SimpleDateFormat dtInputFormat = new SimpleDateFormat("MM'/'dd'/'yyyy' 'HH':'mm':'ss");
		curView = new InputView("Start Date/Time (MM/DD/YYYY HH:MM:SS): ");
		curView.addViewListener(new ViewListener<String>() {
			public void onViewResult(ViewEvent<String> evt) {
				try {
					DateTime dtStart = new DateTime(dtInputFormat.parse(evt.getResult()).getTime());
					eventInfo.startDateTime = new Property<DateTime>("DTSTART", dtStart);
				} catch (ParseException e) {
					evt.getSource().show();
				}
			}
		});
		curView.show();
		// End DateTime
		curView = new InputView("End Date/Time (MM/DD/YYYY HH:MM:SS): ");
		curView.addViewListener(new ViewListener<String>() {
			public void onViewResult(ViewEvent<String> evt) {
				try {
					DateTime dtEnd = new DateTime(dtInputFormat.parse(evt.getResult()).getTime());
					eventInfo.endDateTime = new Property<DateTime>("DTEND", dtEnd);
				} catch (ParseException e) {
					evt.getSource().show();
				}
			}
		});
		curView.show();
		// TimeZone Name
		curView = new InputView("Time Zone Name: ");
		curView.addViewListener(new ViewListener<String>() {
			public void onViewResult(ViewEvent<String> evt) {
				tzInfo.name = new Property<String>("TZNAME", evt.getResult());
			}
		});
		curView.show();
		// Daylight Saving Time
		curView = new InputView("Time Zone is Daylight Saving Time (true/false): ");
		curView.addViewListener(new ViewListener<String>() {
			public void onViewResult(ViewEvent<String> evt) {
				tzInfo.isDst = Boolean.parseBoolean(evt.getResult());
			}
		});
		curView.show();
		// TimeZone ID
		curView = new InputView("Time Zone ID: ");
		curView.addViewListener(new ViewListener<String>() {
			public void onViewResult(ViewEvent<String> evt) {
				tzInfo.id = new Property<String>("TZID", evt.getResult());
			}
		});
		curView.show();
		// TimeZone Offset
		curView = new InputView("Time Zone UTC Offset: ");
		curView.addViewListener(new ViewListener<String>() {
			public void onViewResult(ViewEvent<String> evt) {
				tzInfo.offsetFrom = new Property<String>("OFFSETFROM", evt.getResult());
				tzInfo.offsetTo = new Property<String>("OFFSETTO", evt.getResult());
			}
		});
		curView.show();
		// Build event.
		TimeZone tz = new TimeZone(tzInfo.name, tzInfo.id, tzInfo.offsetFrom, tzInfo.offsetTo, tzInfo.isDst, 
				new CalendarComponentInfo());
		eventInfo.timeZone = new Property<TimeZone>("VTIMEZONE", tz);
		return new Event(eventInfo);
	}
	
	private class TimeZoneInfo {
		public Property<String> name;
		public Property<String> id;
		public Property<String> offsetFrom;
		public Property<String> offsetTo;
		public boolean isDst;
	}
	
}
